package com.maas.util.mybatis.jpa.littlenb.support;

import com.littlenb.mybatisjpa.statement.StatementFactory;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;

import com.maas.util.mybatis.annotations.Mapper;
import com.maas.util.mybatis.jpa.littlenb.annotation.mapper.SelectDefinition;
import com.maas.util.mybatis.jpa.littlenb.annotation.mapper.SelectPageDefinition;
import com.maas.util.mybatis.jpa.littlenb.common.scanner.AnnotationTypeFilterBuilder;
import com.maas.util.mybatis.jpa.littlenb.common.scanner.SpringClassScanner;
import com.maas.util.mybatis.jpa.littlenb.support.core.PersistentEnhancer;
import com.maas.util.mybatis.jpa.littlenb.support.core.PersistentResultMapEnhancer;
import org.apache.ibatis.builder.IncompleteElementException;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.builder.annotation.MethodResolver;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.Configuration;
import org.reflections.Reflections;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.springframework.core.type.filter.TypeFilter;

import javax.persistence.Entity;

/**
 * mapper 注解声明扫描器
 * MybatisJpaInitializer 中加载  AnnotationStatementScanner
 * @author sway.li
 **/
public class AnnotationStatementScanner {

  private Configuration configuration;

  private String[] basePackages;

  private String[] entityPackageArr;


  //private AnnotationStatementRegistry annotationStatementRegistry;
  //改成自定义注册器
  private MyAnnotationStatementRegistry annotationStatementRegistry;
  public void scanV1() {
    for (String basePackage : basePackages) {
      Reflections reflections = new Reflections(basePackage, new TypeAnnotationsScanner(),
          new SubTypesScanner(), new MethodAnnotationsScanner());
      Set<Class<?>> mappers = reflections.getTypesAnnotatedWith(Mapper.class);

      for (Class<?> mapperClass : mappers) {
        /** mybatis */
        String resource = mapperClass.getName().replace(".", "/") + ".java (best guess)";

        MapperBuilderAssistant assistant = new MapperBuilderAssistant(configuration, resource);;


        Method[] methods = mapperClass.getMethods();
        for (Method method : methods) {
          Annotation[] annotations = method.getDeclaredAnnotations();
          for (Annotation annotation : annotations) {
            //用 AnnotationStatementRegistry 解析mapper 里的注解
            StatementFactory statementFactory = annotationStatementRegistry
                .findFactory(annotation.annotationType());

             if (statementFactory != null) {
              MappedStatement statement = statementFactory.parseStatement(configuration, method, mapperClass);
              //一个MappedStatement对象对应Mapper配置文件中的一个select/update/insert/delete节点
              configuration.addMappedStatement(statement);

            }
          }

        }
      }


    }

    parsePendingMethods();
  }

  public void scanEntity(){
    for (String entityPackage : entityPackageArr) {
      /** scan entity **/
      TypeFilter entityFilter = AnnotationTypeFilterBuilder.build(Entity.class);
      SpringClassScanner entityScanner = new SpringClassScanner.Builder().scanPackage(entityPackage)
              .typeFilter(entityFilter).build();
      Set<Class<?>> entitySet = null;
      try {
        entitySet = entityScanner.scan();
      } catch (ClassNotFoundException | IOException e) {
        // log or throw runTimeExp
        throw new RuntimeException(e);
      }
      if (entitySet != null && !entitySet.isEmpty()) {
        for (Class<?> entity : entitySet) {
          // resultMap enhance
          PersistentResultMapEnhancer resultMapEnhancer = new PersistentResultMapEnhancer(configuration, entity);
          try {
            resultMapEnhancer.enhance();
          } catch (IllegalStateException e) {
            e.printStackTrace();
            throw e;
          }
        }
        // parsePendingMethods(configuration);
      }
    }

  }

  /***
   * 扫描实体类 和mapper
   * 原理：
   * 自动添加Statement 类似 mybatis 的 xml
   * 其余的事情交回 mybatis 处理
   */
  public void scan() {


    for (String basePackage : basePackages) {
      Reflections reflections = new Reflections(basePackage, new TypeAnnotationsScanner(),
              new SubTypesScanner(), new MethodAnnotationsScanner());
      Set<Class<?>> mappers = reflections.getTypesAnnotatedWith(Mapper.class);


      for (Class<?> mapperClass : mappers) {
        Method[] methods = mapperClass.getMethods();
        for (Method method : methods) {
          Annotation[] annotations = method.getDeclaredAnnotations();
          for (Annotation annotation : annotations) {
            //用 AnnotationStatementRegistry 解析mapper 里的注解
            StatementFactory statementFactory = annotationStatementRegistry
                    .findFactory(annotation.annotationType());

            if (statementFactory != null) {

              Class annotationType =annotation.annotationType();

              //TODO 使用容器装载 实现了MyStatementBuildable接口 的类
              //判断是否实现了MyStatementBuildable接口，PersistentEnhancer
              if(annotationType.equals(SelectDefinition.class)||annotationType.equals(SelectPageDefinition.class)){
                /**
                 * 实现了MyStatementBuildable接口，用 PersistentEnhancer 来处理
                 * 持久数据转化javabean 时需要用到
                 */
                PersistentEnhancer mapperEnhancer = new PersistentEnhancer(configuration, mapperClass,statementFactory,method);
                mapperEnhancer.enhance();
              }else{
                /**
                 * 没实现了MyStatementBuildable接口，直接生成statement
                 */
                MappedStatement statement = statementFactory.parseStatement(configuration, method, mapperClass);
                //一个MappedStatement对象对应Mapper配置文件中的一个select/update/insert/delete节点
                configuration.addMappedStatement(statement);
              }
            }
          }

        }
      }
    }

//    Collection<String> list=configuration.getKeyGeneratorNames();
//    for (String  str:list) {
//      System.out.println(str);
//    }
    parsePendingMethods();
  }

  private void parsePendingMethods() {
    Collection<MethodResolver> incompleteMethods = configuration.getIncompleteMethods();
    synchronized (incompleteMethods) {
      Iterator<MethodResolver> iter = incompleteMethods.iterator();
      while (iter.hasNext()) {
        try {
          iter.next().resolve();
          iter.remove();
        } catch (IncompleteElementException e) {
          // This method is still missing a resource
        }
      }
    }
  }

  public static class Builder {

    private AnnotationStatementScanner instance = new AnnotationStatementScanner();

    public Builder() {
    }

    public Builder configuration(Configuration configuration) {
      this.instance.configuration = configuration;
      return this;
    }

    public Builder basePackages(String[] basePackages) {
      this.instance.basePackages = basePackages;
      return this;
    }

    public Builder annotationStatementRegistry(MyAnnotationStatementRegistry annotationStatementRegistry) {
      this.instance.annotationStatementRegistry = annotationStatementRegistry;
      return this;
    }

    public Builder entityPackageArr(String[] entityPackageArr) {
      this.instance.entityPackageArr = entityPackageArr;
      return this;
    }
    public AnnotationStatementScanner build() {
      return this.instance;
    }
  }

}
